#ifndef XGE_XASSERT_H_
#define XGE_XASSERT_H_
#include "xge_common_config.h"
#include <string.h>

//$Revision: 2011/12/23
//1. Add more features ( XASSERT_BINARY macro to do the binary assertion )
//$

namespace xge {    
  
  namespace xge_internal {
    void Assertion(
      const char_t* file ,
      const char_t* func ,
      size_t line,
      const char_t* expression  
      );
    void Assertion( 
      const char_t* file ,
      const char_t* func ,
      size_t line,
      const char_t* expression ,
      const char_t* format ,
      ...
      );
  } //namespace internal 

}
// Export macro

#ifdef _DEBUG
#define XASSERT(Expression) (void)( !!(Expression) || ( xge::xge_internal::Assertion( __X__FILE__, __X__FUNC__  , __LINE__ , _xT(#Expression)  ),0) )
#define XASSERT_SAY(Expression ,FormatString ,  ...) (void) ( !!(Expression) || ( xge::xge_internal::Assertion( __X__FILE__ , __X__FUNC__ , __LINE__ , _xT(#Expression) , FormatString , __VA_ARGS__ ),0) )
#define XVERYFIY(Expression) do { XASSERT(Expression); } while(0)
#else
#define XASSERT(Expression) (void)(0)
#define XASSERT_SAY(Expression,FormatString,...) (void)(0)
#define XVERYFIY(Expression) do { if(Expression){} } while(0)
#endif

// Compile time assertion
namespace xge{
  namespace xge_internal{

    template <bool result> struct StaticAssertionResult{};
    struct StaticAssertionDummyStruct{};
    template <> struct StaticAssertionResult<true> {
      typedef StaticAssertionDummyStruct Static_Error_Messsage_Occur ;
    };

  }
}
// Compile time assertion
#define STATIC_ASSERT(x) \
  typedef xge::xge_internal::StaticAssertionResult<(bool)(x)>::Static_Error_Messsage_Occur CompileError
// Check slow
// This just another wrapper 
// since it warning us that such check is very slow ! So we must remove it in the release version 
// Typically , check the thread binding stuff is very slow , it involves the lock operation 
// so use it only in debug mode .
#define XASSERT_SLOW(Expression) XASSERT(Expression)
#define XASSERT_SLOW_SAY(Expression,FormatString,...) XASSERT_SAY(Expression,FormatString,__VA_ARGS__)
// Some other useful macro to expand
// For pod type , since the non-pod type like string or const char_t* varies different for the operation
#define POD_ASSERT_BINARY_OP(Left,Right,Operation,FType) XASSERT_SAY( \
  (Left) Operation (Right),_xT("LeftValue=") FType _xT(";RightValue=") FType _xT("!\n"),(Left),(Right) )
// A simple wrapper for the string type
#define STR_ASSERT_BINARY_OP(Operation,LeftValue,RightValue) \
  XASSERT_SAY(Operation,_xT("LeftValue=%s;RightValue=%s!\n"),(LeftValue),(RightValue))
// for the wide char support
#ifdef XGE_USE_WIDE_CHAR
#define xstrcmp wcscmp
#else
#define xstrcmp strcmp
#endif
// EQ type implementation
#define X_ASSERT_EQ_INT(Left,Right)     POD_ASSERT_BINARY_OP(Left,Right,==,_xT("%d"))
#define X_ASSERT_EQ_FLOAT(Left,Right)   POD_ASSERT_BINARY_OP(Left,Right,==,_xT("%f"))
#define X_ASSERT_EQ_CHAR(Left,Right)    POD_ASSERT_BINARY_OP(Left,Right,==,_xT("%c")) 
#define X_ASSERT_EQ_STRING(Left,Right)  STR_ASSERT_BINARY_OP(xstrcmp((Left),(Right))==0,(Left),(Right))
#define X_ASSERT_EQ_XSTRING(Left,Right) STR_ASSERT_BINARY_OP((Left)==(Right),(Left).c_str(),(Right).c_str())
// NEQ type implementation
#define X_ASSERT_NEQ_INT(Left,Right)     POD_ASSERT_BINARY_OP(Left,Right,!=,_xT("%d"))
#define X_ASSERT_NEQ_FLOAT(Left,Right)   POD_ASSERT_BINARY_OP(Left,Right,!=,_xT("%f"))
#define X_ASSERT_NEQ_CHAR(Left,Right)    POD_ASSERT_BINARY_OP(Left,Right,!=,_xT("%c"))
#define X_ASSERT_NEQ_STRING(Left,Right)  STR_ASSERT_BINARY_OP(xstrcmp((Left),(Right))!=0,(Left),(Right))
#define X_ASSERT_NEQ_XSTRING(Left,Right) STR_ASSERT_BINARY_OP((Left)!=(Right),(Left).c_str(),(Right).c_str())
// > type implementation 
#define X_ASSERT_BIGGER_INT(Left,Right)    POD_ASSERT_BINARY_OP(Left,Right,>,_xT("%d"))
#define X_ASSERT_BIGGER_FLOAT(Left,Right)  POD_ASSERT_BINARY_OP(Left,Right,>,_xT("%f"))
#define X_ASSERT_BIGGER_CHAR(Left,Right)   POD_ASSERT_BINARY_OP(Left,Right,>,_xT("%c"))
#define X_ASSERT_BIGGER_STRING(Left,Right) STR_ASSERT_BINARY_OP(xstrcmp((Left),(Right))>0,(Left),(Right))
#define X_ASSERT_BIGGER_XSTRING(Left,Right) STR_ASSERT_BINARY_OP((Left)>(Right),(Left).c_str(),(Right).c_str())
// >= type implementation
#define X_ASSERT_NOTLESS_INT(Left,Right)    POD_ASSERT_BINARY_OP(Left,Right,>=,_xT("%d"))
#define X_ASSERT_NOTLESS_FLOAT(Left,Right)  POD_ASSERT_BINARY_OP(Left,Right,>=,_xT("%f"))
#define X_ASSERT_NOTLESS_CHAR(Left,Right)   POD_ASSERT_BINARY_OP(Left,Right,>=,_xT("%c"))
#define X_ASSERT_NOTLESS_STRING(Left,Right) STR_ASSERT_BINARY_OP(xstrcmp((Left),(Right))>=0,(Left),(Right))
#define X_ASSERT_NOTLESS_XSTRING(Left,Right) STR_ASSERT_BINARY_OP((Left)>=(Right),(Left).c_str(),(Right).c_str())
// < type implementation
#define X_ASSERT_LESS_INT(Left,Right)    POD_ASSERT_BINARY_OP(Left,Right,<,_xT("%d"))
#define X_ASSERT_LESS_FLOAT(Left,Right)  POD_ASSERT_BINARY_OP(Left,Right,<,_xT("%f"))
#define X_ASSERT_LESS_CHAR(Left,Right)   POD_ASSERT_BINARY_OP(Left,Right,<,_xT("%c"))
#define X_ASSERT_LESS_STRING(Left,Right) STR_ASSERT_BINARY_OP(xstrcmp((Left),(Right))<0,(Left),(Right))
#define X_ASSERT_LESS_XSTRING(Left,Right) STR_ASSERT_BINARY_OP((Left)<(Right),(Left).c_str(),(Right).c_str())
// <= type implementation
#define X_ASSERT_NOTBIGGER_INT(Left,Right)    POD_ASSERT_BINARY_OP(Left,Right,<=,_xT("%d"))
#define X_ASSERT_NOTBIGGER_FLOAT(Left,Right)  POD_ASSERT_BINARY_OP(Left,Right,<=,_xT("%f"))
#define X_ASSERT_NOTBIGGER_CHAR(Left,Right)   POD_ASSERT_BINARY_OP(Left,Right,<=,_xT("%c"))
#define X_ASSERT_NOTBIGGER_STRING(Left,Right) STR_ASSERT_BINARY_OP(xstrcmp((Left),(Right))<=0,(Left),(Right))
#define X_ASSERT_NOTBIGGER_XSTRING(Left,Right) STR_ASSERT_BINARY_OP((Left)<=(Right),(Left).c_str(),(Right).c_str())
// xstrcmp undef avoid pollute the namespace
#undef xstrcmp
// The binary assertion macro 
// Example:
// Assert for the not bigger
// XString a , b;
// XASSERT_BINARY(NOTBIGGER,XSTRING,a,b);
// The Operation Type:
// NOTBIGGER : <=
// NOTLESS   : >=
// BIGGER    : >
// LESS      : <
// EQ        : =
// NEQ       : !=
// The support type :
// CHAR      : char_t
// STRING    : const char_t* 
// XSTRING   : XString
// INT       : int   ( size_t )
// FLOAT     : float ( double )

#define XASSERT_BINARY(BinaryOperation,Type,Left,Right) X_ASSERT_##BinaryOperation##_##Type(Left,Right)


#endif// XGE_XASSERT_H_